package chaoxing_netdisk

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/chicken-team-outside/chicken_transmission/utils"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

const userAgent = "chaoxingCloudDisk/chaoxingCloudDisk_4_1000087_4.3.9.25533_windows_pc_202308062039_1 (iPhone; iOS 11.0.2; zh_CN)_15717942248989221422"

var uuidRegexp = regexp.MustCompile(`<input type = "hidden" value="(\w+)" id = "uuid"/>`)
var encRegexp = regexp.MustCompile(`<input type = "hidden" value="(\w+)" id = "enc"/>`)
var qrRegexp = regexp.MustCompile(`<img src="(\S+)" alt="" id="ewm"/>`)
var usernameRegexp = regexp.MustCompile(`<p class="personalName" title="(\S+)"`)

type QrLoginResponse struct {
	QrUrl string `json:"qr_url"`
	Enc   string `json:"enc,omitempty"`
	Uuid  string `json:"uuid,omitempty"`
}

func getResult(re *regexp.Regexp, data []byte) string {
	subMatch := re.FindSubmatch(data)
	if len(subMatch) > 1 {
		return string(subMatch[1])
	}
	return ""
}

func GetLoginQr(ctx context.Context) (*QrLoginResponse, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://passport2.chaoxing.com/cloudscanlogin?width=192&height=192", nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", userAgent)
	rsp, err := utils.GetHttpClient().Do(req)
	if err != nil {
		return nil, err
	}
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("invalid status code: %d", rsp.StatusCode)
	}
	body, err := io.ReadAll(rsp.Body)
	if err != nil {
		return nil, err
	}
	result := &QrLoginResponse{
		Uuid:  getResult(uuidRegexp, body),
		Enc:   getResult(encRegexp, body),
		QrUrl: "https://passport2.chaoxing.com" + getResult(qrRegexp, body),
	}
	resp, _ := http.Get(result.QrUrl)
	if resp != nil {
		resp.Body.Close()
	}
	return result, nil
}

type AuthInfo struct {
	Lv         string `json:"lv"`
	Fid        string `json:"fid"`
	Uid        string `json:"_uid"`
	Uf         string `json:"uf"`
	D          string `json:"_d"`
	UID        string `json:"UID"`
	Vc         string `json:"vc"`
	Vc2        string `json:"vc2"`
	Vc3        string `json:"vc3"`
	CxPToken   string `json:"cx_p_token"`
	Xxtenc     string `json:"xxtenc"`
	DsstashLog string `json:"DSSTASH_LOG"`
}

type scanResult struct {
	Uid      string `json:"uid"`
	Nickname string `json:"nickname"`
	Mes      string `json:"mes"`
	Type     string `json:"type"`
	Status   bool   `json:"status"`
}

var ErrUserCancelLogin = errors.New("用户手机端取消登录")
var ErrQrExpired = errors.New("二维码已失效")

func GetAuthStatus(ctx context.Context, enc, uuid string) (*AuthInfo, error) {
	form := url.Values{}
	form.Add("enc", enc)
	form.Add("uuid", uuid)
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://passport2.chaoxing.com/getauthstatus", strings.NewReader(form.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", userAgent)
	rsp, err := utils.GetHttpClient().Do(req)
	if err != nil {
		return nil, err
	}
	if rsp.StatusCode != http.StatusOK {
		return nil, StatusError(rsp.StatusCode)
	}
	result := new(scanResult)
	err = json.NewDecoder(rsp.Body).Decode(result)
	if err != nil {
		return nil, err
	}
	if result.Status {
		info := new(AuthInfo)
		for _, v := range rsp.Cookies() {
			switch v.Name {
			case "lv":
				info.Lv = v.Value
			case "fid":
				info.Fid = v.Value
			case "_uid":
				info.Uid = v.Value
			case "uf":
				info.Uf = v.Value
			case "_d":
				info.D = v.Value
			case "UID":
				info.UID = v.Value
			case "vc":
				info.Vc = v.Value
			case "vc2":
				info.Vc2 = v.Value
			case "vc3":
				info.Vc3 = v.Value
			case "cx_p_token":
				info.CxPToken = v.Value
			case "xxtenc":
				info.Xxtenc = v.Value
			case "DSSTASH_LOG":
				info.DsstashLog = v.Value
			}
		}
		return info, nil
	} else if result.Type == "6" {
		return nil, ErrUserCancelLogin
	} else if result.Type == "2" {
		return nil, ErrQrExpired
	}
	return nil, nil
}
